// 一些关于平面几何的板子

const eps = 1e-7;

function dcmp(x) {
    if (Math.abs(x) < eps) return 0;
    return (x < 0 ? -1 : 1);
}

// 点
// x: 横坐标
// y: 纵坐标
function Point(a) {
    this.x = a[0];
    this.y = a[1];
    this.len2 = function () {
        return this.x * this.x + this.y * this.y;
    }
}

// 线段
// s: 点1
// e: 点2
function Line(s, e) {
    this.s = s;
    this.e = e;
}

// 点积
// a: Point
// b: Point
// return a dot b
function dot(a, b) {
    return a.x * b.x + a.y * b.y;
}

// 叉积
// a: Point
// b: Point
// return a x b
function cross(a, b) {
    return a.x * b.y - a.y * b.x;
}

// 点减法
// a: Point
// b: Point
// return a - b
function pointSub(a, b) {
    return new Point([a.x - b.x, a.y - b.y]);
}

// 点乘常数
// a: Point
// k: value
// return k * a
function pointMult(k, a) {
    return new Point([k * a.x, k * a.y]);
}

// 点加法
// a: Point
// b: Point
// return a + b
function pointAdd(a, b) {
    return new Point([a.x + b.x, a.y + b.y]);
}

// 线段相交判断
// 返回值 2:规范相交 1:不规范相交 0:不相交
// a: Point
// v: Point
function seg_cross_seg(a, v) {
    let d1, d2, d3, d4;
    d1 = dcmp(cross(pointSub(a.e, a.s), pointSub(v.s, a.s)));
    d2 = dcmp(cross(pointSub(a.e, a.s), pointSub(v.e, a.s)));
    d3 = dcmp(cross(pointSub(v.e, v.s), pointSub(a.s, v.s)));
    d4 = dcmp(cross(pointSub(v.e, v.s), pointSub(a.e, v.s)));

    if ((d1 ^ d2) === -2 && (d3 ^ d4) === -2) return 2;
    return (d1 === 0 && dcmp(dot(pointSub(v.s, a.s), pointSub(v.s, a.e))) <= 0) ||
        (d2 === 0 && dcmp(dot(pointSub(v.e, a.s), pointSub(v.e, a.e))) <= 0) ||
        (d3 === 0 && dcmp(dot(pointSub(a.s, v.s), pointSub(a.s, v.e))) <= 0) ||
        (d4 === 0 && dcmp(dot(pointSub(a.e, v.s), pointSub(a.e, v.e))) <= 0);
}

// 点在直线上的投影
// p: Point
// a: Line
function projection(p, a) {//点在直线上的投影
    let newP = pointMult(dot(pointSub(a.e, a.s), pointSub(p, a.s)), pointSub(a.e, a.s));
    return pointAdd(pointMult(1.0 / (pointSub(a.e, a.s).len2()), newP), a.s)
}

// 点排序比较算法
function PointCompare(a, b) {
    if (a.x === b.x) {
        if (a.y < b.y) return -1;
        else return 1;
    }
    if (a.x < b.x) return -1;
    else return 1;
}

// 点排序
function PointSort(a) {
    return a.sort(PointCompare)
}

// 求线段的法向量(单点表示法，表示从(0,0)起点的法向量)
// line: Line
function getNormalVec(line) {
    //首先确定法向量的倾斜角k
    let k = Math.atan2(line.e.y - line.s.y, line.e.x - line.s.x);
    k = k - Math.PI / 2;
    if (dcmp(k - Math.PI / 2) === 0) {
        return new Point([0, 100]);
    } else {
        return new Point([1000, Math.tan(k) * 1000]);
    }
}

export {Point, Line, getNormalVec, projection, PointSort, seg_cross_seg, dcmp}
